package com.lonely.purchase.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.annotation.RedisLock;
import com.lonely.common.core.domain.BaseEntity;
import com.lonely.common.core.domain.Select;
import com.lonely.common.core.domain.StatusInfo;
import com.lonely.common.core.page.Condition;
import com.lonely.common.enums.CommonStatus;
import com.lonely.common.enums.DataScope;
import com.lonely.common.exception.BusinessException;
import com.lonely.common.threadlocals.DataPermissionThreadLocal;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.common.utils.enums.ExtractStatusInfoUtil;
import com.lonely.goods.domain.entity.SysGoods;
import com.lonely.goods.domain.entity.SysGoodsPartMaterial;
import com.lonely.goods.domain.entity.SysMaterial;
import com.lonely.goods.domain.entity.SysMaterialItem;
import com.lonely.goods.service.IGoodsPartMaterialService;
import com.lonely.goods.service.IMaterialItemService;
import com.lonely.goods.service.IMaterialService;
import com.lonely.order.domain.dto.api.GetBigGoodsBomReqDTO;
import com.lonely.order.domain.dto.api.GetBigGoodsBomResDTO;
import com.lonely.order.domain.entity.SysOrder;
import com.lonely.order.domain.entity.SysOrderPartMaterial;
import com.lonely.order.domain.entity.SysSheinOpenApiSecret;
import com.lonely.order.enums.OrderEnum;
import com.lonely.order.service.IMesApiService;
import com.lonely.order.service.IOrderPartMaterialService;
import com.lonely.order.service.IOrderService;
import com.lonely.order.service.ISysSheinOpenApiSecretService;
import com.lonely.product.service.ICuttingBedService;
import com.lonely.purchase.domain.dto.materialpurchase.GoMaterialPurchaseDTO;
import com.lonely.purchase.domain.dto.materialpurchase.QueryMaterialPurchasePageDTO;
import com.lonely.purchase.domain.dto.materialpurchase.RecycledMaterialsDTO;
import com.lonely.purchase.domain.entity.SysMaterialPurchase;
import com.lonely.purchase.domain.entity.SysRemainingMaterialInventory;
import com.lonely.purchase.domain.entity.SysRemainingMaterialInventoryLog;
import com.lonely.purchase.domain.vo.materialpurchase.QueryMaterialPurchasePageVO;
import com.lonely.purchase.enums.MaterialPurchaseEnum;
import com.lonely.purchase.mapper.SysMaterialPurchaseMapper;
import com.lonely.purchase.service.IMaterialPurchaseDeductionReplenishService;
import com.lonely.purchase.service.IMaterialPurchaseService;
import com.lonely.purchase.service.IRemainingMaterialInventoryLogService;
import com.lonely.purchase.service.IRemainingMaterialInventoryService;
import com.lonely.system.service.ISysCustomerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : 黄志标
 * @date: 2025/7/18 17:47
 * @description: 订单物料采购服务实现类
 */
@Service
@Slf4j
public class MaterialPurchaseServiceImpl extends ServiceImpl<SysMaterialPurchaseMapper, SysMaterialPurchase> implements IMaterialPurchaseService {

    @Autowired
    private IMesApiService mesApiService;

    @Autowired
    private ISysSheinOpenApiSecretService sheinOpenApiSecretService;

    @Autowired
    private IMaterialService materialService;

    @Autowired
    private IMaterialItemService materialItemService;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private ICuttingBedService cuttingBedService;

    @Autowired
    private IOrderPartMaterialService orderPartMaterialService;

    @Autowired
    private IGoodsPartMaterialService goodsPartMaterialService;

    @Autowired
    private IMaterialPurchaseDeductionReplenishService materialPurchaseDeductionReplenishService;

    @Autowired
    private ISysCustomerService customerService;

    @Autowired
    private IRemainingMaterialInventoryService remainingMaterialInventoryService;

    @Autowired
    private IRemainingMaterialInventoryLogService remainingMaterialInventoryLogService;

    /**
     * 分页查询
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<QueryMaterialPurchasePageVO> page(QueryMaterialPurchasePageDTO queryDto) {
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        Page<QueryMaterialPurchasePageVO> page = Condition.page(queryDto);
        page = super.getBaseMapper().page(page, queryDto);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            List<Long> materialPurchaseIds = page.getRecords().stream().map(QueryMaterialPurchasePageVO::getId).collect(Collectors.toList());

            // 统计每个物料的扣损总数量和补料总数量
            Map<Long, Tuple> materialDeductionReplenishQuantityMap = this.materialPurchaseDeductionReplenishService.getMaterialPurchaseDeductionReplenishQuantityMap(materialPurchaseIds);

            // 获取每个物料对应的客户的价格浮动最大范围
            List<Long> customerIds = page.getRecords().stream().map(QueryMaterialPurchasePageVO::getCustomerId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<Long, String> customerMaxRangeMap = this.customerService.getCustomerMaxRangeMap(customerIds);

            page.setRecords(page.getRecords().stream().peek(purchase -> {
                // 计算计划量,公式  下单数 * (1+ 损耗/100) * 单件用量
                BigDecimal loss = NumberUtil.div(StrUtil.nullToDefault(purchase.getSupplierLoss(), "0"), "100"); // 损耗
                BigDecimal placeOrderNum = NumberUtil.toBigDecimal(ObjectUtil.defaultIfNull(purchase.getPlaceOrderNum(), 0)); // 下单数
                BigDecimal simpleUse = NumberUtil.toBigDecimal(StrUtil.nullToDefault(purchase.getSimpleUse(), "0")); // 单件用量
                BigDecimal plannedQuantity = NumberUtil.mul(placeOrderNum, NumberUtil.add(1, loss), simpleUse);

                // 设置计划量
                purchase.setPlannedQuantity(NumberUtil.round(plannedQuantity, 2).toString());

                // 计算 计划采购金额, 公式 参考单价 * 单件用量 * （1+损耗）* 下单数 * （1+ 最大浮动范围/100）
                BigDecimal price = NumberUtil.toBigDecimal(StrUtil.blankToDefault(purchase.getPrice(), "0")); // 参考单价
                BigDecimal maxRange = NumberUtil.div(customerMaxRangeMap.getOrDefault(purchase.getCustomerId(), "0"), "100"); // 最大浮动范围
                BigDecimal plannedPurchaseAmount = NumberUtil.mul(price, simpleUse, NumberUtil.add(1, loss), placeOrderNum, NumberUtil.add(1, maxRange));
                purchase.setPlannedPurchaseAmount(NumberUtil.round(plannedPurchaseAmount, 2).toString());

                // 计算 实际采购金额, 公式 回料数量 * 回料价
                BigDecimal actualPurchaseAmount = NumberUtil.mul(purchase.getRecycledMaterialsPrice(), purchase.getRecycledMaterialsVolume());
                purchase.setActualPurchaseAmount(NumberUtil.round(actualPurchaseAmount, 2).toString());

                // 计算 下单采购金额, 公式 采购数量 * 采购价
                BigDecimal purchaseAmount = NumberUtil.mul(purchase.getPurchasePrice(), purchase.getPurchaseVolume());
                purchase.setPlaceOrderPurchaseAmount(NumberUtil.round(purchaseAmount, 2).toString());

                // 设置扣损/补料数量
                if (materialDeductionReplenishQuantityMap.containsKey(purchase.getId())) {
                    Tuple quantitys = materialDeductionReplenishQuantityMap.get(purchase.getId());

                    // 设置总扣损数
                    purchase.setDeductionQuantity(StrUtil.equals(quantitys.get(0), "0") ? null : quantitys.get(0));

                    // 设置总补料数
                    purchase.setReplenishQuantity(StrUtil.equals(quantitys.get(1), "0") ? null : quantitys.get(1));
                }


            }).collect(Collectors.toList()));

        }
        return page;
    }

    /**
     * 获取采购供应商下拉列表
     *
     * @param supplierName
     * @return
     */
    @Override
    public List<Select> getPurchaseSupplierSelects(String supplierName) {
        if (StrUtil.isBlank(supplierName)) {
            return new ArrayList<>();
        }
        List<String> supplierNames = super.getBaseMapper().getPurchaseSupplierSelects(supplierName);
        return supplierNames.stream().filter(StrUtil::isNotBlank).map(x -> new Select().setValue(x).setLabel(x)).collect(Collectors.toList());
    }

    /**
     * 采购
     *
     * @param goMaterialPurchases
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedisLock(key = "'materialPurchase:goPurchase'", waitTime = 5000L)
    public void goPurchase(List<GoMaterialPurchaseDTO> goMaterialPurchases) {
        if (CollUtil.isEmpty(goMaterialPurchases)) {
            return;
        }

        // 校验占用数不能超过余料数
        List<Long> materialPurchaseIds = goMaterialPurchases.stream().map(GoMaterialPurchaseDTO::getId).distinct().collect(Collectors.toList());
        List<SysMaterialPurchase> sysMaterialPurchases = super.listByIds(materialPurchaseIds);
        List<String> materialSkus = sysMaterialPurchases.stream().map(SysMaterialPurchase::getMaterialSku).distinct().collect(Collectors.toList());
        List<SysRemainingMaterialInventory> remainingMaterialInventories = this.remainingMaterialInventoryService.list(new LambdaQueryWrapper<SysRemainingMaterialInventory>()
                .in(SysRemainingMaterialInventory::getMaterialSku, materialSkus)
                .eq(SysRemainingMaterialInventory::getStatus, CommonStatus.ENABLE.code)
        );
        if (CollUtil.isEmpty(remainingMaterialInventories)) {
            // 没有查询到对应的余料库存数，则不允许传入占用数
            long count = goMaterialPurchases.stream().filter(x -> StrUtil.isNotBlank(x.getOccupancyQuantity())).filter(x -> Convert.toBigDecimal(x.getOccupancyQuantity()).compareTo(BigDecimal.ZERO) > 0).count();
            Assert.isTrue(count == 0, "参数有误,没有查询到余料库存数信息");
        }

        // 物料sku的语料库存数映射
        Map<String, BigDecimal> skuRemainingMaterialQuantityMap = remainingMaterialInventories.stream().collect(Collectors.toMap(SysRemainingMaterialInventory::getMaterialSku, x -> Convert.toBigDecimal(x.getRemainingMaterialQuantity()), (x, y) -> x));

        // 输入的物料采购的 占用数映射
        Map<Long, BigDecimal> inputMaterialOccupancyQuantityMap = goMaterialPurchases.stream().filter(x -> StrUtil.isNotBlank(x.getOccupancyQuantity())).collect(Collectors.toMap(GoMaterialPurchaseDTO::getId, x -> Convert.toBigDecimal(x.getOccupancyQuantity())));

        Map<String, BigDecimal> totalMaterialOccupancyQuantityMap = new HashMap<>();
        for (SysMaterialPurchase materialPurchase : sysMaterialPurchases) {
            // 当前物料采购的 余料数
            BigDecimal remainingMaterialQuantity = skuRemainingMaterialQuantityMap.getOrDefault(materialPurchase.getMaterialSku(), BigDecimal.ZERO);
            // 当前物料采购 的占用数
            BigDecimal occupancyQuantity = inputMaterialOccupancyQuantityMap.getOrDefault(materialPurchase.getId(), BigDecimal.ZERO);

            if (totalMaterialOccupancyQuantityMap.containsKey(materialPurchase.getMaterialSku())) {
                BigDecimal alreadyQuantity = totalMaterialOccupancyQuantityMap.getOrDefault(materialPurchase.getMaterialSku(), BigDecimal.ZERO);
                BigDecimal totalQuantity = NumberUtil.add(alreadyQuantity, occupancyQuantity);
                if (totalQuantity.compareTo(remainingMaterialQuantity) > 0) {
                    throw new BusinessException("物料 [" + materialPurchase.getMaterialSku() + "] 的占用总数超过余料库存");
                }
                totalMaterialOccupancyQuantityMap.put(materialPurchase.getMaterialSku(), totalQuantity);
            } else {
                totalMaterialOccupancyQuantityMap.put(materialPurchase.getMaterialSku(), occupancyQuantity);
            }
        }

        // 入库
        Map<Long, SysMaterialPurchase> materialPurchaseMap = sysMaterialPurchases.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity(), (x, y) -> x));
        Map<String, Long> materialSkuIdMap = remainingMaterialInventories.stream().collect(Collectors.toMap(SysRemainingMaterialInventory::getMaterialSku, BaseEntity::getId, (x, y) -> x));
        List<SysRemainingMaterialInventoryLog> remainingMaterialInventoryLogs = new ArrayList<>();
        for (GoMaterialPurchaseDTO goMaterialPurchaseDTO : goMaterialPurchases) {
            SysMaterialPurchase materialPurchase = materialPurchaseMap.get(goMaterialPurchaseDTO.getId());
            Assert.notNull(materialPurchase, "采购信息不存在");

            if (!Objects.equals(materialPurchase.getStatus(), MaterialPurchaseEnum.MaterialPurchaseStatusEnum.TO_BE_PURCHASED.getStatus())) {
                throw new BusinessException("当前采购记录不是待采购状态");
            }

            // 更新状态
            materialPurchase.setStatus(MaterialPurchaseEnum.MaterialPurchaseStatusEnum.TO_BE_RECYCLED_MATERIALS.getStatus());

            // 更新采购价格信息
            materialPurchase.setPurchasePrice(goMaterialPurchaseDTO.getPurchasePrice());
            materialPurchase.setPurchaseVolume(goMaterialPurchaseDTO.getPurchaseVolume());
            materialPurchase.setPurchaser(SecurityUtils.getUserId());

            super.updateById(materialPurchase);

            // 构建余料库存操作日志对象
            if (StrUtil.isNotBlank(goMaterialPurchaseDTO.getOccupancyQuantity()) && NumberUtil.isGreater(Convert.toBigDecimal(goMaterialPurchaseDTO.getOccupancyQuantity()), BigDecimal.ZERO)) {
                SysRemainingMaterialInventoryLog remainingMaterialInventoryLog = new SysRemainingMaterialInventoryLog();
                remainingMaterialInventoryLog.setRemainingMaterialInventoryId(materialSkuIdMap.getOrDefault(materialPurchase.getMaterialSku(), null));
                remainingMaterialInventoryLog.setLogTitle(String.format("订单号：%s 物料采购占用库存数：%s(%s)", materialPurchase.getProduceOrderId(), goMaterialPurchaseDTO.getOccupancyQuantity(), materialPurchase.getUnit()));
                remainingMaterialInventoryLog.setLogBody(null);
                remainingMaterialInventoryLog.setCreateBy(SecurityUtils.getUserId());
                remainingMaterialInventoryLog.setUpdateBy(SecurityUtils.getUserId());
                remainingMaterialInventoryLogs.add(remainingMaterialInventoryLog);
            }
        }

        // 扣除余料库存数
        for (SysRemainingMaterialInventory remainingMaterialInventory : remainingMaterialInventories) {
            if (!totalMaterialOccupancyQuantityMap.containsKey(remainingMaterialInventory.getMaterialSku())) {
                continue;
            }

            BigDecimal remainingMaterialQuantityBigDecimal = Convert.toBigDecimal(remainingMaterialInventory.getRemainingMaterialQuantity());
            BigDecimal currentMaterialOccupancyQuantity = totalMaterialOccupancyQuantityMap.get(remainingMaterialInventory.getMaterialSku());
            if (NumberUtil.isLessOrEqual(currentMaterialOccupancyQuantity, remainingMaterialQuantityBigDecimal)) {
                remainingMaterialInventory.setRemainingMaterialQuantity(NumberUtil.sub(remainingMaterialQuantityBigDecimal, currentMaterialOccupancyQuantity).stripTrailingZeros().toPlainString());
                remainingMaterialInventory.setUpdateBy(SecurityUtils.getUserId());
            } else {
                throw new BusinessException("物料 [" + remainingMaterialInventory.getMaterialSku() + "] 的占用总数超过余料库存");
            }
        }
        this.remainingMaterialInventoryService.updateBatchById(remainingMaterialInventories);

        // 添加余料库存操作日志
        if (CollUtil.isNotEmpty(remainingMaterialInventoryLogs)) {
            this.remainingMaterialInventoryLogService.saveBatch(remainingMaterialInventoryLogs);
        }
    }

    /**
     * 获取物料采购单位
     *
     * @param id
     * @return
     */
    @Override
    public String getMaterialPurchaseUnit(Long id) {
        SysMaterialPurchase materialPurchase = super.getById(id);
        Assert.notNull(materialPurchase, "采购信息不存在");

        // 判断是同步的订单还是本地订单采购
        MaterialPurchaseEnum.PurchaseTypeEnum purchaseTypeEnum = MaterialPurchaseEnum.PurchaseTypeEnum.getByType(materialPurchase.getType());
        switch (purchaseTypeEnum) {
            case SHEIN:
                return getShellMaterialPurchaseUnit(materialPurchase);
            case LOCAL:
                return getLocalMaterialPurchaseUnit(materialPurchase);
        }
        return null;
    }

    /**
     * 回料
     *
     * @param recycledMaterialsDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recycledMaterials(RecycledMaterialsDTO recycledMaterialsDTO) {
        SysMaterialPurchase materialPurchase = super.getById(recycledMaterialsDTO.getId());
        Assert.notNull(materialPurchase, "采购信息不存在");

        if (!Objects.equals(materialPurchase.getStatus(), MaterialPurchaseEnum.MaterialPurchaseStatusEnum.TO_BE_RECYCLED_MATERIALS.getStatus())) {
            throw new BusinessException("当前采购记录不是待回料状态");
        }

        // 更新状态
        materialPurchase.setStatus(MaterialPurchaseEnum.MaterialPurchaseStatusEnum.COMPLETED.getStatus());

        // 更新回料价格信息
        materialPurchase.setRecycledMaterialsPrice(recycledMaterialsDTO.getRecycledMaterialsPrice());
        materialPurchase.setRecycledMaterialsVolume(recycledMaterialsDTO.getRecycledMaterialsVolume());

        if (StrUtil.isNotBlank(recycledMaterialsDTO.getSupplierName())) {
            materialPurchase.setSupplierName(recycledMaterialsDTO.getSupplierName());
        }
        super.updateById(materialPurchase);

        // 判断当前订单下的所有采购单都变成已完成状态
        if (currentOrderAllPurchaseCompleted(materialPurchase.getProduceOrderId())) {

            // 判断是否已生成过裁剪单,一个订单只能生成一个裁床数据
            boolean alreadyExistsCuttingBed = this.cuttingBedService.alreadyExistsCuttingBed(materialPurchase.getProduceOrderId());
            if (!alreadyExistsCuttingBed) {

                // 生成裁床单
                this.cuttingBedService.createToBeLabelRackCuttingBed(materialPurchase);

                // 修改订单状态
                this.orderService.notifyCuttingBed(materialPurchase.getProduceOrderId());
            }
        }
    }

    /**
     * 通知裁床
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void notifyCuttingBed(Long id) {
        SysMaterialPurchase materialPurchase = super.getById(id);
        Assert.notNull(materialPurchase, "采购信息不存在");

        if (!Objects.equals(materialPurchase.getStatus(), MaterialPurchaseEnum.MaterialPurchaseStatusEnum.COMPLETED.getStatus())) {
            throw new BusinessException("当前采购记录不是已完成状态");
        }

        // 一个订单只能生成一个裁床数据
        boolean alreadyExistsCuttingBed = this.cuttingBedService.alreadyExistsCuttingBed(materialPurchase.getProduceOrderId());
        Assert.isFalse(alreadyExistsCuttingBed, "该订单已生成裁床数据");

        // 修改订单状态
        this.orderService.notifyCuttingBed(materialPurchase.getProduceOrderId());

        // 生成待排唛架状态的裁床单
        this.cuttingBedService.createToBeLabelRackCuttingBed(materialPurchase);
    }

    /**
     * 创建采购单
     *
     * @param orders
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createPurchaseByOrders(List<SysOrder> orders) {
        for (SysOrder order : orders) {
            List<SysOrderPartMaterial> orderPartMaterials = this.orderPartMaterialService.list(new LambdaQueryWrapper<SysOrderPartMaterial>()
                    .eq(SysOrderPartMaterial::getOrderId, order.getId())
                    .eq(SysOrderPartMaterial::getGoodsColor, order.getColor())
            );
            if (CollUtil.isEmpty(orderPartMaterials)) {
                continue;
            }

            // 获取当前用户对应的工厂和客户信息
            SysSheinOpenApiSecret openApiSecret = this.sheinOpenApiSecretService.getByFactoryId(SecurityUtils.getFactoryId());
            Assert.notNull(openApiSecret, "该工厂未配置密钥信息");

            List<SysMaterialPurchase> materialPurchases = new ArrayList<>();
            for (SysOrderPartMaterial orderPartMaterial : orderPartMaterials) {
                SysMaterialPurchase sysMaterialPurchase = new SysMaterialPurchase();
                sysMaterialPurchase.setOrderId(order.getId());
                sysMaterialPurchase.setSourceGoodsMaterialId(orderPartMaterial.getSourceGoodsMaterialId());
                sysMaterialPurchase.setType(null);
                sysMaterialPurchase.setProduceOrderId(order.getProduceOrderId());
                sysMaterialPurchase.setMaterialColor(orderPartMaterial.getMaterialColor());
                sysMaterialPurchase.setMaterialName(orderPartMaterial.getMaterialName());
                sysMaterialPurchase.setMaterialSku(orderPartMaterial.getMaterialSku());
                sysMaterialPurchase.setMaterialType(orderPartMaterial.getMaterialTypeName());
                sysMaterialPurchase.setPrice(orderPartMaterial.getUnitPrice());
                sysMaterialPurchase.setPurchaseCode(null);
                sysMaterialPurchase.setPurchaseType(orderPartMaterial.getItem());
                sysMaterialPurchase.setUnit(orderPartMaterial.getUnit());
                sysMaterialPurchase.setSimpleUse(orderPartMaterial.getSinglePieceUsage());
                sysMaterialPurchase.setSingleAmountKg(null);
                sysMaterialPurchase.setSupplierAddr(orderPartMaterial.getSupplierAddress());
                sysMaterialPurchase.setSupplierCode(orderPartMaterial.getSupplierCode());
                sysMaterialPurchase.setSupplierColorCode(orderPartMaterial.getSupplierColorCode());
                sysMaterialPurchase.setSupplierLoss(orderPartMaterial.getLoss());
                sysMaterialPurchase.setSupplierName(orderPartMaterial.getSupplierName());
                sysMaterialPurchase.setSupplierPhone(orderPartMaterial.getSupplierPhone());
                sysMaterialPurchase.setWeight(orderPartMaterial.getGramWeight());
                sysMaterialPurchase.setWidth(orderPartMaterial.getBorderedDoorWidth());
                sysMaterialPurchase.setStatus(MaterialPurchaseEnum.MaterialPurchaseStatusEnum.TO_BE_PURCHASED.getStatus());
                sysMaterialPurchase.setFactoryId(openApiSecret.getFactoryId());
                sysMaterialPurchase.setCustomerId(openApiSecret.getCustomerId());
                sysMaterialPurchase.setPurchasePrice(null);
                sysMaterialPurchase.setPurchaseVolume(null);
                sysMaterialPurchase.setPurchaser(null);
                sysMaterialPurchase.setRecycledMaterialsPrice(null);
                sysMaterialPurchase.setRecycledMaterialsVolume(null);
                sysMaterialPurchase.setCreateBy(SecurityUtils.getUserId());
                sysMaterialPurchase.setUpdateBy(SecurityUtils.getUserId());
                materialPurchases.add(sysMaterialPurchase);
            }

            super.saveBatch(materialPurchases);
        }


    }

    /**
     * 同步商品报价单的物料
     * <p>
     * 业务：修改商品报价单后，需要将该商品对应的所有订单产生的采购单(状态为待采购的)的物料信息同步
     * <p>
     * TODO 该接口已作废
     *
     * @param sysGoods
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Deprecated
    public void synchronizedGoodsQuotationSheetPartMaterials(SysGoods sysGoods) {
        // 1. 获取该sku对应的所有状态为待采购的订单信息
        List<SysOrder> sysOrders = this.orderService.list(new LambdaQueryWrapper<SysOrder>()
                .eq(SysOrder::getSku, sysGoods.getSkc())
                .eq(SysOrder::getStatusInt, OrderEnum.OrderStatus.TO_BE_PURCHASED.getStatus())
        );
        if (CollUtil.isEmpty(sysOrders)) {
            log.debug("该sku:{}下没有待采购的订单信息", sysGoods.getSkc());
            return;
        }

        //2. 获取该sku下的所有商品部件物料信息
        List<SysGoodsPartMaterial> sysGoodsPartMaterials = this.goodsPartMaterialService.list(new LambdaQueryWrapper<SysGoodsPartMaterial>()
                .eq(SysGoodsPartMaterial::getGoodsId, sysGoods.getId())
        );
        if (CollUtil.isEmpty(sysGoodsPartMaterials)) {
            log.debug("该sku:{}下没有商品部件物料数据", sysGoods.getSkc());
            return;
        }

        //3. 获取指定订单下待采购的采购单信息
        List<Long> productOrderIds = sysOrders.stream().map(SysOrder::getProduceOrderId).distinct().collect(Collectors.toList());
        List<SysMaterialPurchase> toBePurchasedDatas = super.list(new LambdaQueryWrapper<SysMaterialPurchase>()
                .in(SysMaterialPurchase::getProduceOrderId, productOrderIds)
                .eq(SysMaterialPurchase::getStatus, MaterialPurchaseEnum.MaterialPurchaseStatusEnum.TO_BE_PURCHASED.getStatus())
        );
        if (CollUtil.isEmpty(toBePurchasedDatas)) {
            log.debug("该订单:{} 下没有待采购的采购单信息", sysGoods.getSkc());
            return;
        }

        //4. 删除所有的采购单，重新生成
        List<Long> needRemovePurchaseIds = toBePurchasedDatas.stream().map(BaseEntity::getId).collect(Collectors.toList());
        super.removeByIds(needRemovePurchaseIds);

        //5. 重新生成采购单信息
        List<SysMaterialPurchase> newAddMaterialPurchases = new ArrayList<>();
        for (SysOrder sysOrder : sysOrders) {
            for (SysGoodsPartMaterial sysGoodsPartMaterial : sysGoodsPartMaterials) {
                SysMaterialPurchase sysMaterialPurchase = new SysMaterialPurchase();
                sysMaterialPurchase.setOrderId(sysOrder.getId());
                sysMaterialPurchase.setSourceGoodsMaterialId(null);
                sysMaterialPurchase.setType(null);
                sysMaterialPurchase.setProduceOrderId(sysOrder.getProduceOrderId());
                sysMaterialPurchase.setMaterialColor(sysGoodsPartMaterial.getMaterialColor());
                sysMaterialPurchase.setMaterialName(sysGoodsPartMaterial.getMaterialName());
                sysMaterialPurchase.setMaterialSku(sysGoodsPartMaterial.getMaterialSku());
                sysMaterialPurchase.setMaterialType(sysGoodsPartMaterial.getMaterialTypeName());
                sysMaterialPurchase.setPrice(sysGoodsPartMaterial.getUnitPrice());
                sysMaterialPurchase.setPurchaseCode(null);
                sysMaterialPurchase.setPurchaseType(sysGoodsPartMaterial.getItem());
                sysMaterialPurchase.setUnit(sysGoodsPartMaterial.getUnit());
                sysMaterialPurchase.setSimpleUse(sysGoodsPartMaterial.getSinglePieceUsage());
                sysMaterialPurchase.setSingleAmountKg(null);
                sysMaterialPurchase.setSupplierAddr(sysGoodsPartMaterial.getSupplierAddress());
                sysMaterialPurchase.setSupplierCode(sysGoodsPartMaterial.getSupplierCode());
                sysMaterialPurchase.setSupplierColorCode(sysGoodsPartMaterial.getSupplierColorCode());
                sysMaterialPurchase.setSupplierLoss(sysGoodsPartMaterial.getLoss());
                sysMaterialPurchase.setSupplierName(sysGoodsPartMaterial.getSupplierName());
                sysMaterialPurchase.setSupplierPhone(sysGoodsPartMaterial.getSupplierPhone());
                sysMaterialPurchase.setWeight(sysGoodsPartMaterial.getGramWeight());
                sysMaterialPurchase.setWidth(sysGoodsPartMaterial.getBorderedDoorWidth());
                sysMaterialPurchase.setStatus(MaterialPurchaseEnum.MaterialPurchaseStatusEnum.TO_BE_PURCHASED.getStatus());
                sysMaterialPurchase.setFactoryId(sysOrder.getFactoryId());
                sysMaterialPurchase.setCustomerId(sysOrder.getCustomerId());
                sysMaterialPurchase.setPurchasePrice(null);
                sysMaterialPurchase.setPurchaseVolume(null);
                sysMaterialPurchase.setPurchaser(null);
                sysMaterialPurchase.setRecycledMaterialsPrice(null);
                sysMaterialPurchase.setRecycledMaterialsVolume(null);
                sysMaterialPurchase.setId(null);
                sysMaterialPurchase.setCreateBy(SecurityUtils.getUserId());
                sysMaterialPurchase.setUpdateBy(SecurityUtils.getUserId());
                newAddMaterialPurchases.add(sysMaterialPurchase);
            }
        }
        super.saveBatch(newAddMaterialPurchases);
    }

    /**
     * 获取物料采购状态信息
     *
     * @param queryDto
     * @return
     */
    @Override
    public List<StatusInfo> getStatusInfo(QueryMaterialPurchasePageDTO queryDto) {
        // 去除状态过滤
        queryDto.setPurchaseStatus(null);
        // 添加数据权限过滤
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        List<StatusInfo> statusTotals = super.getBaseMapper().getStatusTotals(queryDto);
        return ExtractStatusInfoUtil.extractStatusInfos(statusTotals, MaterialPurchaseEnum.MaterialPurchaseStatusEnum.values());
    }

    /**
     * 判断当前订单下的所有采购单都变成已完成状态
     *
     * @param produceOrderId
     * @return
     */
    private boolean currentOrderAllPurchaseCompleted(Long produceOrderId) {
        int count = super.count(new LambdaQueryWrapper<SysMaterialPurchase>()
                .eq(SysMaterialPurchase::getProduceOrderId, produceOrderId)
                .ne(SysMaterialPurchase::getStatus, MaterialPurchaseEnum.MaterialPurchaseStatusEnum.COMPLETED.getStatus())
        );
        return count == 0;
    }


    /**
     * 获取本地物料采购单位
     *
     * @param materialPurchase
     * @return
     */
    private String getLocalMaterialPurchaseUnit(SysMaterialPurchase materialPurchase) {
        SysMaterialItem materialItem = this.materialItemService.getOne(new LambdaQueryWrapper<SysMaterialItem>()
                .eq(SysMaterialItem::getSku, materialPurchase.getMaterialSku())
        );
        if (materialItem == null) {
            return null;
        }

        SysMaterial sysMaterial = this.materialService.getById(materialItem.getMaterialId());
        if (sysMaterial == null) {
            return null;
        }
        return sysMaterial.getUnit();
    }


    /**
     * 获取shell物料采购单位
     *
     * @param materialPurchase
     * @return
     */
    private String getShellMaterialPurchaseUnit(SysMaterialPurchase materialPurchase) {
        SysSheinOpenApiSecret openApiSecret = this.sheinOpenApiSecretService.getByFactoryId(materialPurchase.getFactoryId());
        Assert.notNull(openApiSecret, "该工厂未配置密钥信息");

        GetBigGoodsBomReqDTO reqDTO = new GetBigGoodsBomReqDTO();
        reqDTO.setProduceOrderId(Convert.toInt(materialPurchase.getProduceOrderId()));
        GetBigGoodsBomResDTO bigGoodsBom = this.mesApiService.getBigGoodsBom(openApiSecret, reqDTO);
        GetBigGoodsBomResDTO.BigGoodsBom skuBom = bigGoodsBom.getBigGoodsBom().stream().filter(x -> Objects.equals(x.getMaterialSku(), materialPurchase.getMaterialSku()))
                .findFirst().orElse(null);
        if (skuBom == null) {
            // 没有找到对应的bom信息
            return null;
        }
        return skuBom.getUnit();
    }

}
